package com.question.business.auth.service.impl;

import com.question.business.auth.model.ao.LoginAO;
import com.question.business.auth.model.dto.CurrentUserDTO;
import com.question.business.auth.model.dto.UserDetailDTO;
import com.question.business.auth.model.vo.LoginVO;
import com.question.business.auth.service.IAuthService;
import com.question.business.user.service.IUserService;
import com.question.common.exception.BusinessException;
import com.question.common.utils.CurrentUserUtil;
import com.question.common.utils.DateUtil;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.CredentialsExpiredException;
import org.springframework.security.authentication.LockedException;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Service;

import java.util.Objects;
import java.util.UUID;

/**
 * 认证服务实现类
 *
 * @author star
 * @since 2022/8/12
 */
@Slf4j
@Service
@AllArgsConstructor
public class AuthServiceImpl implements IAuthService {

    private final AuthenticationManager authenticationManager;

    private final CurrentUserUtil currentUserUtil;

    private final IUserService userService;

    /**
     * 账号密码登陆认证
     *
     * @param ao 登陆数据
     * @return LoginVo
     */
    @Override
    public LoginVO userLogin(LoginAO ao) {
        LoginVO vo = new LoginVO();
        try {
            //生成token
            String token = UUID.randomUUID().toString();
            final Authentication authentication = authenticationManager.authenticate(new UsernamePasswordAuthenticationToken(ao.getUsername(), ao.getPassword()));
            //存储认证信息
            SecurityContextHolder.getContext().setAuthentication(authentication);
            UserDetailDTO userDetail = (UserDetailDTO) authentication.getPrincipal();
            //存储用户信息
            currentUserUtil.setUser(token, userDetail);
            vo.setRole(userDetail.getRoles());
            vo.setToken(token);
            vo.setExpire(Objects.isNull(userDetail.getExpire()) ? null : DateUtil.diffDate(userDetail.getExpire()) - 1);
            userService.unlockUser(userDetail.getId());
        } catch (CredentialsExpiredException e) {
            log.error("登陆认证失败，账号已过期：", e);
            throw new BusinessException("账号已过期");
        } catch (LockedException e) {
            log.error("登陆认证失败，账号已锁定：", e);
            throw new BusinessException("账号已锁定");
        } catch (Exception e) {
            log.error("登陆认证失败：", e);
            userService.changeLoginErrorNumber(ao.getUsername());
            throw new BusinessException("账户或密码错误");
        }
        return vo;
    }

    /**
     * 退出登陆认证
     */
    @Override
    public void loginOut() {
        currentUserUtil.logOut();
        SecurityContextHolder.clearContext();
    }

    /**
     * 获取当前用户信息
     *
     * @return CurrentUserDTO
     */
    @Override
    public CurrentUserDTO currentUser() {
        UserDetailDTO detail = currentUserUtil.getUser();
        CurrentUserDTO current = new CurrentUserDTO();
        BeanUtils.copyProperties(detail, current);
        return current;
    }

}
